//
//  ViewController.swift
//  MyColorPicker
//
//  Created by 火星人 on 2018/9/18.
//  Copyright © 2018年 火星人. All rights reserved.
//

import Cocoa
import StoreKit

var tmpFile = NSHomeDirectory() + "/tmp.png"
let userDefaults = NSUserDefaultsController.shared.defaults

class ViewController: NSViewController, NSTextFieldDelegate {
    
    var pvc: NSWindowController?
    var cvc: NSWindowController?
    var colorLayers = [CALayer]()
    @IBOutlet weak var colorListView: ColorListView!
    @IBOutlet weak var codeView0: NSView!
    @IBOutlet weak var codeLabel0: NSTextField!
    @IBOutlet weak var codeView1: NSView!
    @IBOutlet weak var codeLabel1: NSTextField!
    @IBOutlet weak var codeView2: NSView!
    @IBOutlet weak var codeLabel2: NSTextField!
    @IBOutlet weak var codeEditButton0: NSButton!
    @IBOutlet weak var codeEditButton1: NSButton!
    @IBOutlet weak var codeEditButton2: NSButton!
    @IBOutlet weak var colorBorderView: NSView!
    @IBOutlet weak var colorWell: NSColorWell!
    @IBOutlet weak var rTextField: NSTextField!
    @IBOutlet weak var gTextField: NSTextField!
    @IBOutlet weak var bTextField: NSTextField!
    @IBOutlet weak var hexTextField: NSTextField!
    
    let copiedTitle = NSAttributedString(string: "Copied", attributes: [
        .foregroundColor : NSColor(red: 0.000, green: 0.703, blue: 0.321, alpha: 1.00)
        ])
    let noneTitle = NSAttributedString(string: "", attributes: [
        .foregroundColor : NSColor(red: 0.000, green: 0.703, blue: 0.321, alpha: 1.00)
        ])
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.colorWell.addObserver(self, forKeyPath: "color", options: .new, context: nil)
        self.colorWell.wantsLayer = true
        self.colorWell.layer?.borderWidth = self.colorWell.frame.height * 0.5
        self.colorWell.layer?.borderColor = CGColor.black
        
        self.colorBorderView.wantsLayer = true
        self.colorBorderView.layer?.backgroundColor = CGColor.white
        
        self.restoreColor()
        self.setCodeView()
        self.updateValues(self.colorWell.color.cgColor)
        
        self.hexTextField.delegate = self
        self.rTextField.delegate = self
        self.gTextField.delegate = self
        self.bTextField.delegate = self
        
        setupMenu()
        setupColors()
    }
    
    private func setupColors(){
        var colors = [
            NSColor.red.cgColor,
            NSColor.orange.cgColor,
            NSColor.yellow.cgColor,
            NSColor.green.cgColor,
            NSColor.cyan.cgColor,
            NSColor.blue.cgColor,
            NSColor.purple.cgColor,
            NSColor.magenta.cgColor,
            NSColor.brown.cgColor,
            CGColor(red: 0.63, green: 0.63, blue: 0.63, alpha: 1.00),
            CGColor(red: 0.45, green: 0.45, blue: 0.45, alpha: 1.00),
            CGColor(red: 0.29, green: 0.29, blue: 0.29, alpha: 1.00),
            CGColor(red: 0.07, green: 0.07, blue: 0.07, alpha: 1.00),
            CGColor(red: 0, green: 0, blue: 0, alpha: 1.00),
            ]
        if let cs = userDefaults.array(forKey: "colors") {
            if cs.count > 0 {
                for i in 0 ..< cs.count {
                    if let com = cs[i] as? [CGFloat] {
                        let color = CGColor(red: com[0], green: com[1], blue: com[2], alpha: 1)
                        colors.insert(color, at: 0)
                    }
                }
            }
        }
        let padding = CGFloat(2)
        let wh = self.colorListView.frame.height - padding * 2
        if self.colorLayers.count == 0 {
            var x = padding
            for i in 1...1000 {
                let frame = CGRect(x: x, y: padding, width: wh, height: wh)
                let layer = CALayer()
                layer.frame = frame
                if i >= colors.count {
                    layer.backgroundColor = CGColor(red: 0, green: 0, blue: 0, alpha: 1.00)
                }
                else {
                    layer.backgroundColor = colors[i - 1]
                }
                self.colorListView.layer?.addSublayer(layer)
                self.colorLayers.append(layer)
                x += wh + padding
                if x > self.colorListView.frame.width {
                    break
                }
            }
        }
        else {
            for i in 0...self.colorLayers.count - 1 {
                let layer = colorLayers[i]
                layer.backgroundColor = colors[i]
            }
        }
        
        if self.colorListView.mouseDownHandle == nil {
            weak var wself = self
            self.colorListView.mouseDownHandle = {
                (event: NSEvent) in
                
                if let wself = wself {
                    let x = event.locationInWindow.x - wself.colorListView.frame.origin.x
                    let index = Int(x/(wh + padding))
                    if let color = NSColor(cgColor: wself.colorLayers[index].backgroundColor!) {
                        wself.colorWell.color = color
                    }
                }
            }
        }
        
    }
    
    private func setupMenu(){
//  preferences
        var menu = NSApplication.shared.mainMenu?.item(at: 0)?.submenu?.item(at: 2)
        menu?.target = self
        menu?.action = #selector(self.go2preferences)
        
//        show main window
        menu = NSApplication.shared.mainMenu?.item(at: 2)?.submenu?.item(at: 0)
        menu?.target = self
        menu?.action = #selector(self.showMainWindow)
        
//        show color panel
        menu = NSApplication.shared.mainMenu?.item(at: 2)?.submenu?.item(at: 1)
        menu?.target = self
        menu?.action = #selector(self.showColorPanel)
        
//        pick color
        menu = NSApplication.shared.mainMenu?.item(at: 2)?.submenu?.item(at: 2)
        menu?.target = self
        menu?.action = #selector(self.show)
        
//        help
        menu = NSApplication.shared.mainMenu?.item(at: 3)?.submenu?.item(at: 0)
        menu?.target = self
        menu?.action = #selector(self.help)
        
//        rating the app
        menu = NSApplication.shared.mainMenu?.item(at: 3)?.submenu?.item(at: 1)
        menu?.target = self
        menu?.action = #selector(self.ratingTheApp)
        
//        Suggestions for developer
        menu = NSApplication.shared.mainMenu?.item(at: 3)?.submenu?.item(at: 2)
        menu?.target = self
        menu?.action = #selector(self.suggestions)
        
//        share the app
        menu = NSApplication.shared.mainMenu?.item(at: 3)?.submenu?.item(at: 4)
        menu?.target = self
        menu?.action = #selector(self.share)
        
//        save color
        menu = NSApplication.shared.mainMenu?.item(at: 1)?.submenu?.item(at: 7)
        menu?.target = self
        menu?.action = #selector(self.saveColor)
        
//        reset colors
        menu = NSApplication.shared.mainMenu?.item(at: 1)?.submenu?.item(at: 8)
        menu?.target = self
        menu?.action = #selector(self.resetColors)
    }
    
    @objc private func resetColors(){
        userDefaults.removeObject(forKey: "colors")
        self.setupColors()
    }
    
    @objc private func help(){
        let alert = NSAlert()
        alert.alertStyle = .informational
        alert.messageText = "If you have any questions, please send an email to me, thank you."
        alert.addButton(withTitle: "Send")
        alert.addButton(withTitle: "Cancel")
        let res = alert.runModal()
        if res == .alertFirstButtonReturn {
            let emailService = NSSharingService.init(named: .composeEmail)
            emailService?.recipients = ["568852859@qq.com"]
            emailService?.subject = "MyColorPicker Help"
            emailService?.perform(withItems: [])
        }
    }
    
    @objc private func share(){
        NSWorkspace.shared.open(URL(string: "macappstore://itunes.apple.com/app/id1437472834?mt=12")!)
    }
    
    @objc private func ratingTheApp(){
        if #available(OSX 10.14, *) {
            SKStoreReviewController.requestReview()
        } else {
            NSWorkspace.shared.open(URL(string: "macappstore://itunes.apple.com/app/id1437472834?mt=12")!)
        }
    }
    
    @objc private func suggestions(){
        let alert = NSAlert()
        alert.alertStyle = .informational
        alert.messageText = "If you have any suggestions for developers, please send an email for them, thank you."
        alert.addButton(withTitle: "Send")
        alert.addButton(withTitle: "Cancel")
        let res = alert.runModal()
        if res == .alertFirstButtonReturn {
            let emailService = NSSharingService.init(named: .composeEmail)
            emailService?.recipients = ["568852859@qq.com"]
            emailService?.subject = "Suggestions for developers"
            emailService?.perform(withItems: [])
        }
    }
    
    @objc private func showMainWindow(){
        self.view.window?.windowController?.showWindow(nil)
    }
    override func viewWillAppear() {
        weak var wself = self
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .milliseconds(10)) {
            wself?.hexTextField.isEnabled = true
            wself?.rTextField.isEnabled = true
            wself?.gTextField.isEnabled = true
            wself?.bTextField.isEnabled = true
        }
        
        self.hexTextField.isEnabled = false
        self.rTextField.isEnabled = false
        self.gTextField.isEnabled = false
        self.bTextField.isEnabled = false
        
        self.hexTextField.backgroundColor = .white
        self.hexTextField.textColor = NSColor(red: 0.15, green: 0.16, blue: 0.16, alpha: 1.00)
        
        self.rTextField.backgroundColor = self.hexTextField.backgroundColor
        self.rTextField.textColor = self.hexTextField.textColor
        self.gTextField.backgroundColor = self.hexTextField.backgroundColor
        self.gTextField.textColor = self.hexTextField.textColor
        self.bTextField.backgroundColor = self.hexTextField.backgroundColor
        self.bTextField.textColor = self.hexTextField.textColor
        
        // 设置光标颜色
        (view.window?.fieldEditor(true, for: "rrr") as? NSTextView)?.insertionPointColor = NSColor(red: 0.15, green: 0.16, blue: 0.16, alpha: 1.00)
    }
    
    private func setCodeView(){
        self.codeView0.wantsLayer = true
        self.codeView0.layer?.backgroundColor = CGColor.white
        self.codeLabel0.textColor = NSColor(calibratedRed: 0.273, green: 0.275, blue: 0.275, alpha: 1.00)
        self.codeLabel0.font = NSFont(name: "System", size: 8)
        
        self.codeView1.wantsLayer = true
        self.codeView1.layer?.backgroundColor = CGColor.white
        self.codeLabel1.textColor = self.codeLabel0.textColor
        self.codeLabel1.font = self.codeLabel0.font
        
        self.codeView2.wantsLayer = true
        self.codeView2.layer?.backgroundColor = CGColor.white
        self.codeLabel2.textColor = self.codeLabel0.textColor
        self.codeLabel2.font = self.codeLabel0.font
        
        self.codeLabel0.placeholderString = "edit code format"
        self.codeLabel1.placeholderString = self.codeLabel0.placeholderString
        self.codeLabel2.placeholderString = self.codeLabel0.placeholderString
        
        self.codeLabel0.stringValue = ""
        self.codeLabel1.stringValue = ""
        self.codeLabel2.stringValue = ""
        
        self.codeLabel0.maximumNumberOfLines = 1
        self.codeLabel0.lineBreakMode = .byTruncatingTail
        
        self.codeLabel1.maximumNumberOfLines = 1
        self.codeLabel1.lineBreakMode = .byTruncatingTail
        
        self.codeLabel2.maximumNumberOfLines = 1
        self.codeLabel2.lineBreakMode = .byTruncatingTail
        
        
        self.colorListView.wantsLayer = true
        self.colorListView.layer?.backgroundColor = CGColor.white
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == "color" {
            updateValues((object as! NSColorWell).color.cgColor)
        }
    }
    
    @IBAction func pickColorOutside(_ sender: Any) {
        self.show()
    }
    
    @objc func show() {
        let ad = NSApp.delegate as? AppDelegate
        if let picking = ad?.pickingColor, picking {
            return
        }
        else{
            ad?.pickingColor = true
        }
        // 隐藏本窗口
        if userDefaults.string(forKey: "hideWindowWhenPickColor") == "hideWindowWhenPickColor" {
            self.view.window?.orderOut(self)
        }
        // 保存桌面文件
        
        let delay = DispatchTime.now() + .milliseconds(10)
        weak var wself = self
        DispatchQueue.global().asyncAfter(deadline: delay) {
            wself?.TakeScreensShots(fileName: tmpFile)
            
            DispatchQueue.main.async {
                wself?.pvc?.close()
                wself?.saveColor()
                
                let storyBoard = NSStoryboard(name: "Main", bundle: nil)
                let screenShotWindow = storyBoard.instantiateController(withIdentifier: "ScreenshotViewController") as? NSWindowController
                
                (screenShotWindow?.contentViewController as? ScreenshotViewController)?.didPickColor = {
                    (color: CGColor?) -> Void in
                    if let color = color {
                        wself?.updateValues(color)
                        wself?.colorWell.color = NSColor(cgColor: color)!
                        wself?.saveColor()
                    }
                    ad?.pickingColor = false
                }
                
                NSApp.activate(ignoringOtherApps: true)
                screenShotWindow?.window?.level = NSWindow.Level.screenSaver
                screenShotWindow?.showWindow(wself)
            }
        }
    }
    
    private func updateValues(_ color: CGColor){
        self.colorWell.layer?.backgroundColor = color
        self.colorWell.layer?.borderColor = color
        self.hexTextField.stringValue = String(
            format: "%02x%02x%02x",
            Int(color.components![0] * 0xff),
            Int(color.components![1] * 0xff),
            Int(color.components![2] * 0xff)
        )
        self.rTextField.stringValue = "\(Int(color.components![0] * 255.0))"
        self.gTextField.stringValue = "\(Int(color.components![1] * 255.0))"
        self.bTextField.stringValue = "\(Int(color.components![2] * 255.0))"
        
        self.codeLabel0.stringValue = CodeFormatUtils.genCodeWithFormat(format: userDefaults.value(forKey: "codeFormat0") as? [String], colorComponents: color.components)
        
        self.codeLabel1.stringValue = CodeFormatUtils.genCodeWithFormat(format: userDefaults.value(forKey: "codeFormat1") as? [String], colorComponents: color.components)
        
        self.codeLabel2.stringValue = CodeFormatUtils.genCodeWithFormat(format: userDefaults.value(forKey: "codeFormat2") as? [String], colorComponents: color.components)
    }
    
    @IBAction func bgClick(_ sender: Any) {
        self.endEditing()
        NSColorPanel.shared.close()
        self.pvc?.close()
        
        let appDelegate = NSApplication.shared.delegate as? AppDelegate
        appDelegate?.editCodeWindow?.close()
    }
    
    @objc func endEditing(){
        self.hexTextField.abortEditing()
        self.rTextField.abortEditing()
        self.gTextField.abortEditing()
        self.bTextField.abortEditing()
    }
    
    func TakeScreensShots(fileName: String){
        
        var displayCount: UInt32 = 0;
        var result = CGGetActiveDisplayList(0, nil, &displayCount)
        if (result != CGError.success) {
            print("error: \(result)")
            return
        }
        let allocated = Int(displayCount)
        let activeDisplays = UnsafeMutablePointer<CGDirectDisplayID>.allocate(capacity: allocated)
        result = CGGetActiveDisplayList(displayCount, activeDisplays, &displayCount)
        
        if (result != CGError.success) {
            print("error: \(result)")
            return
        }
        
        for i in 1...displayCount {
            let fileUrl = URL(fileURLWithPath: fileName, isDirectory: true)
            let screenShot:CGImage = CGDisplayCreateImage(activeDisplays[Int(i-1)])!
            let bitmapRep = NSBitmapImageRep(cgImage: screenShot)
            let jpegData = bitmapRep.representation(using: NSBitmapImageRep.FileType.png, properties: [:])!
            
            
            do {
                try jpegData.write(to: fileUrl, options: .atomic)
            }
            catch {print("error: \(error)")}
        }
    }
    
    override func viewWillDisappear() {
        NSColorPanel.shared.close()
        self.pvc?.close()
    }
    
    deinit {
        self.colorWell.removeObserver(self, forKeyPath: "color")
    }
    
    @objc private func saveColor(){
        if colorWell.color.cgColor.components == self.colorLayers[0].backgroundColor?.components {
            return
        }
        if var colors = userDefaults.array(forKey: "colors") {
            colors.append(self.colorWell.color.cgColor.components!)
            userDefaults.set(colors, forKey: "colors")
        }
        else{
            userDefaults.set([self.colorWell.color.cgColor.components!], forKey: "colors")
        }
        setupColors()
    }
    
    private func restoreColor(){
        self.hexTextField.stringValue = userDefaults.string(forKey: "hex") ?? "000000"
        self.rTextField.stringValue = userDefaults.string(forKey: "r") ?? "0"
        self.gTextField.stringValue = userDefaults.string(forKey: "g") ?? "0"
        self.bTextField.stringValue = userDefaults.string(forKey: "b") ?? "0"
        
        self.colorWell.color = NSColor(
            red: CGFloat(userDefaults.float(forKey: "rr")),
            green: CGFloat(userDefaults.float(forKey: "gg")),
            blue: CGFloat(userDefaults.float(forKey: "bb")),
            alpha: 1)
        
        NSColorPanel.shared.color = self.colorWell.color
    }
    
    @IBAction func EditCodeFormatAction(_ sender: Any) {
        
        if sender as? NSButton == self.codeEditButton0 {
            self.gotoEditCodeFormatWindow(0)
        }
        else if sender as? NSButton == self.codeEditButton1 {
            self.gotoEditCodeFormatWindow(1)
        }
        else if sender as? NSButton == self.codeEditButton2 {
            self.gotoEditCodeFormatWindow(2)
        }
    }
    
    private func gotoEditCodeFormatWindow(_ from: Int){
        NSColorPanel.shared.close()
        self.pvc?.close()
        self.cvc?.close()
        
        let storyBoard = NSStoryboard(name: "Main", bundle: nil)
        let editCodeWindow = storyBoard.instantiateController(withIdentifier: "EditCodeFormatViewController") as? NSWindowController
        self.cvc = editCodeWindow
        
        let key = "codeFormat\(from)"
        (editCodeWindow?.contentViewController as? EditCodeFormatViewController)?.key = key
        weak var wself = self
        (editCodeWindow?.contentViewController as? EditCodeFormatViewController)?.didSetFormat = {
            wself?.updateValues(wself!.colorWell.color.cgColor)
        }
        editCodeWindow?.showWindow(self)
        
        let appDelegate = NSApplication.shared.delegate as? AppDelegate
        appDelegate?.editCodeWindow = editCodeWindow
    }
    
    @IBAction func copyToClipboard(_ sender: Any) {
        
        NSColorPanel.shared.close()
        self.pvc?.close()
        self.cvc?.close()
        self.endEditing()
        
        let button = sender as! NSButton
        if button.title != "" {
            return
        }
        button.attributedTitle = copiedTitle
        var str = ""
        if button.tag == 1001 {
            str = codeLabel0.stringValue
        }
        else if button.tag == 1002 {
            str = codeLabel1.stringValue
        }
        else if button.tag == 1003 {
            str = codeLabel2.stringValue
        }
        if str == "" {
            return
        }
        else {
            let pb = NSPasteboard.general
            pb.clearContents()
            pb.setString(str, forType: .string)
        }
        button.wantsLayer = true
        button.layer?.backgroundColor = CGColor.white
        
        weak var wself = self
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(1)) {
            if let wself = wself {
                button.layer?.backgroundColor = .clear
                button.attributedTitle = wself.noneTitle
            }
        }
        
        saveColor()
    }
    
    func controlTextDidChange(_ obj: Notification) {
        if obj.object as? NSTextField == self.hexTextField {
            if self.hexTextField.stringValue.count != 6 {
                let value = "0000000" + self.hexTextField.stringValue as NSString
                self.hexTextField.stringValue = value.substring(from: value.length - 6)
            }
            let value = self.hexTextField.stringValue as NSString
            let r = self.hex2Int(hex: value.substring(with: NSRange(location: 0, length: 2)))
            let g = self.hex2Int(hex: value.substring(with: NSRange(location: 2, length: 2)))
            let b = self.hex2Int(hex: value.substring(with: NSRange(location: 4, length: 2)))
            self.rTextField.stringValue = "\(r)"
            self.gTextField.stringValue = "\(g)"
            self.bTextField.stringValue = "\(b)"
            self.updateColorWell(r: r, g: g, b: b)
        }
        else if obj.object as? NSTextField == self.rTextField ||
            obj.object as? NSTextField == self.gTextField ||
            obj.object as? NSTextField == self.bTextField {
            var r = self.str2Int(str: self.rTextField.stringValue)
            var g = self.str2Int(str: self.gTextField.stringValue)
            var b = self.str2Int(str: self.bTextField.stringValue)
            
            if r > 255 {
                r = 255
            }
            if g > 255 {
                g = 255
            }
            if b > 255 {
                b = 255
            }
            self.rTextField.stringValue = "\(r)"
            self.gTextField.stringValue = "\(g)"
            self.bTextField.stringValue = "\(b)"
            
            self.hexTextField.stringValue = String(format: "%02x%02x%02x", r, g, b)
            self.updateColorWell(r: r, g: g, b: b)
        }
    }
    
    private func updateColorWell(r: Int, g: Int, b: Int){
        self.colorWell.color = NSColor(red: CGFloat(r)/255.0, green: CGFloat(g)/255.0, blue: CGFloat(b)/255.0, alpha: 1)
        self.colorWell.layer?.backgroundColor = self.colorWell.color.cgColor
        self.colorWell.layer?.borderColor = self.colorWell.color.cgColor
    }
    
    func hex2Int(hex: String) -> Int {
        if let value = Int(hex, radix: 16) {
            return value
        }
        return 0
    }
    func str2Int(str: String) -> Int {
        if let value = Int(str) {
            return value
        }
        return 0
    }
    
    @objc private func go2preferences(){
        if self.pvc == nil {
            let storyBoard = NSStoryboard(name: "Main", bundle: nil)
            pvc = storyBoard.instantiateController(withIdentifier: "PreferencesViewController") as? NSWindowController
        }
        pvc?.showWindow(self)
    }
    
    @IBAction func closeAction(_ sender: Any) {
        if colorWell.isActive {
            NSColorPanel.shared.close()
        }
        else{
            self.view.window?.close()
        }
    }
    
    @objc private func showColorPanel(){
        let ad = NSApp.delegate as? AppDelegate
        if let picking = ad?.pickingColor, picking {
            return
        }
        self.view.window?.windowController?.showWindow(nil)
        if colorWell.isActive {
            NSColorPanel.shared.close()
        }
        else{
            colorWell.performClick(nil)
        }
    }
}

